package com.zhijian.medical.util;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.util.UriUtils;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 请求签名生成工具
 *
 * @Author chengqing
 * @DateTime 2019年4月16日 下午7:46:01
 * @Version 1.0.1
 */
public class TokenUtil {
    private final static Logger logger = LoggerFactory.getLogger(TokenUtil.class);

    /**
     * 生成http请求token,格式：|TOKEN_VERSION-ak-expirTime|sk|url|method|{qryParam}|{body}|
     *
     * @param tokenBean 签名生成参数
     * @return
     */
    public static String generateToken(TokenBean tokenBean, long expireTime) {
        logger.debug("generateToken| start, ak={},version={},url={},method={},qry={},body={}", tokenBean.getAccessKey(),
                tokenBean.getVersion(), tokenBean.getUrl(), tokenBean.getMethod(), tokenBean.getQryParam(), tokenBean.getBodyParam());
        String token = null;
        //签名生成参数是否合法
//        tokenBean.setExpireTime(expireTime);
        try {
            StringBuilder tokenBuf = new StringBuilder("|")
                    .append(tokenBean.getVersion()).append("-")//version
                    .append(tokenBean.getAccessKey()).append("-")//ak
//                    .append(tokenBean.getExpireTime()).append("|")//expireTime
                    .append(tokenBean.getSecretKey()).append("|")//sk
                    .append(UriUtils.decode(tokenBean.getUrl(), Charset.forName("UTF-8"))).append("|")//url
                    .append(tokenBean.getMethod()).append("|");//method
            //add queryParam
            if (!StringUtils.isEmpty(tokenBean.getQryParam())) {
                StringBuilder qryParam = new StringBuilder();
                List<String> qsArray = new ArrayList<>();
                for (String kv : tokenBean.getQryParam().split("&")) {
                    String[] t = kv.split("=");
                    if (t.length > 1) {
                        qsArray.add(String.format("%s=%s", UriUtils.decode(t[0], Charset.forName("UTF-8")), UriUtils.decode(t[1], Charset.forName("UTF-8"))));
                    } else {
                        qsArray.add(String.format("%s=", UriUtils.decode(t[0], Charset.forName("UTF-8"))));
                    }
                }
                Collections.sort(qsArray);
                for (String s : qsArray) {
                    if (qryParam.length() > 0)
                        qryParam.append("&");
                    qryParam.append(s);
                }
                tokenBuf.append(qryParam.toString());
            }
            tokenBuf.append("|");
            //add body
            if (!StringUtils.isBlank(tokenBean.getBodyParam()))
                tokenBuf.append(tokenBean.getBodyParam()).append("|");
            logger.debug("generateToken| signature={}", tokenBuf.toString());
            //generate token by md5
            token = String.format("%s-%s-%s", tokenBean.getVersion(), 0L, EncryptUtil.md5(tokenBuf.toString()));
            logger.debug("generateToken| end, token={}", token);
        } catch (Exception ex) {
            logger.error("generateToken| exception, ak={},version={},url={},method={},qry={},body={}", tokenBean.getAccessKey(),
                    tokenBean.getVersion(), tokenBean.getUrl(), tokenBean.getMethod(), tokenBean.getQryParam(), tokenBean.getBodyParam());
        }
        return token;
    }

    /**
     * 验证token
     *
     * @param token     待验证签名
     * @param tokenBean 签名生成参数
     * @param isVaild   是否验证
     * @return
     */
    public static boolean validateToken(String token, TokenBean tokenBean, boolean isVaild) {
        logger.debug("validateToken| start, isVaild={}, token={}, ak={},version={},url={},method={},qry={},body={}", isVaild, token, tokenBean.getAccessKey(),
                tokenBean.getVersion(), tokenBean.getUrl(), tokenBean.getMethod(), tokenBean.getQryParam(), tokenBean.getBodyParam());
        //判断签名非空
        boolean vaildFlag = false;
        if (StringUtils.isBlank(token) || token.split("-").length != 3) {
            logger.error("validateToken| error token length");
            return false;
        }
        //补充超时时间
        String[] tokenParts = token.split("-");
//        long expireTime = Long.parseLong(tokenParts[1]);
//        int expireTime = Integer.parseInt(tokenParts[1].length() >= 10 ? tokenParts[1].substring(0, 10) : "0");
//        tokenBean.setExpireTime(expireTime);
        //判断是否验签
        if (!isVaild)
            return true;
        //判断签名是否相等
        if (!tokenBean.getVersion().equals(tokenParts[0])) {
            logger.error("validateToken| invalid token protocol version");
//        } else if (tokenBean.getExpireTime() < System.currentTimeMillis()) {
//            logger.error("validateToken| expired token");
        } else {
            vaildFlag = token.equals(generateToken(tokenBean, 0L));
        }
        logger.debug("validateToken| end, token={}, vaildFlag={}", token, vaildFlag);
        return vaildFlag;
    }

}
